package com.dlc.shop.manager.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayConstants;
import com.alipay.api.domain.*;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.internal.util.codec.Base64;
import com.alipay.api.request.*;
import com.alipay.api.response.AlipayTradeCloseResponse;
import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.binarywang.wxpay.bean.notify.*;
import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.huifu.bspay.sdk.opps.core.request.*;
import com.huifu.bspay.sdk.opps.core.utils.DateTools;
import com.huifu.bspay.sdk.opps.core.utils.SequenceTools;
import com.paypal.orders.OrdersCreateRequest;
import com.dlc.shop.allinpay.config.AllinpayConfig;
import com.dlc.shop.bean.app.param.PayInfoParam;
import com.dlc.shop.bean.bo.PayInfoResultBO;
import com.dlc.shop.bean.bo.RefundInfoBo;
import com.dlc.shop.bean.dto.OrderRefundDto;
import com.dlc.shop.bean.enums.BackType;
import com.dlc.shop.bean.enums.PayStatus;
import com.dlc.shop.bean.enums.RefundKindEnum;
import com.dlc.shop.bean.event.BalancePayEvent;
import com.dlc.shop.bean.event.BalanceRefundEvent;
import com.dlc.shop.bean.model.*;
import com.dlc.shop.bean.model.OrderItem;
import com.dlc.shop.bean.param.PayPalOrderParam;
import com.dlc.shop.bean.param.WebhookParam;
import com.dlc.shop.bean.pay.PayInfoDto;
import com.dlc.shop.bean.pay.RefundInfoDto;
import com.dlc.shop.common.allinpay.bean.OpenRequest;
import com.dlc.shop.common.allinpay.constant.PaySysType;
import com.dlc.shop.common.allinpay.member.resp.AllinpayResp;
import com.dlc.shop.common.allinpay.order.resp.OrderStatusResp;
import com.dlc.shop.common.bean.*;
import com.dlc.shop.common.config.Constant;
import com.dlc.shop.common.constants.SegmentIdKey;
import com.dlc.shop.common.enums.PayType;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.response.ServerResponseEntity;
import com.dlc.shop.common.util.*;
import com.dlc.shop.config.AliPayConfig;
import com.dlc.shop.config.PayPalConfig;
import com.dlc.shop.config.ShopConfig;
import com.dlc.shop.config.WxConfig;
import com.dlc.shop.dao.PayInfoMapper;
import com.dlc.shop.huifu.DemoTestConstants;
import com.dlc.shop.huifu.OppsMerchantConfigDemo;
import com.dlc.shop.service.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.ArrayList;
import java.util.stream.Collectors;

import static com.dlc.shop.huifu.BaseCommonDemo.doExecute;
import static com.dlc.shop.huifu.BaseCommonDemo.doInit;

/**
 * 统一支付工具
 *
 * @author LGH
 */
@Slf4j
@Service
@AllArgsConstructor
public class PayManager {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final AliPayConfig aliPayConfig;

    private final ShopConfig shopConfig;

    private final WxConfig wxConfig;

    private final PayPalConfig payPalConfig;

    private final ApplicationContext applicationContext;

    private final SysConfigService sysConfigService;

    private final PayInfoMapper payInfoMapper;

    private final AllinpayConfig allinpayConfig;

    private final AllinpayManager allinpayManager;

    //  private final OrderService orderService;
    //  private final OrderRefundService orderRefundService;
    //  private final SkuService skuService;
    //  private final ShopDetailService shopDetailService;

    private static final String WX_SUCCESS_XML = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
    private static final String ALI_SUCCESS = "success";
    private static final String SUCCESS = "SUCCESS";
    private static final String TRADE_STATUS = "trade_status";
    private static final String TRADE_SUCCESS = "TRADE_SUCCESS";
    private static final String ALLINPAY_SUCCESS = "OK";
    private static final String REFUND_FEE = "refund_fee";
    private static final String TRADE_CLOSED = "TRADE_CLOSED";
    private static final String REFUND_SUCCESS = "REFUND_SUCCESS";
    private static final String GMT_CLOSE = "gmt_close";
    private static final Long ALLINPAY_ORDER_SUCCESS = 4L;


    public ServerResponseEntity<?> doPay(HttpServletResponse httpResponse, PayInfoDto payInfo) throws WxPayException, AlipayApiException {
        if (payInfo.getPayAmount() < Constant.MIN_PRODUCT_AMOUNT && Objects.equals(payInfo.getPayType(), PayType.SCOREPAY.value())) {
            return ServerResponseEntity.success();
        }
        // 微信支付不能大于1000w
        if (payInfo.getPayAmount() < Constant.MIN_PRODUCT_AMOUNT) {
            // 订单金额有误，无法进行支付
            throw new YamiShopBindException("yami.order.amount.error");
        } else if (payInfo.getPayAmount() > Constant.WECHAT_MAX_PAY_AMOUNT) {
            throw new YamiShopBindException("yami.order.amount.too.large.error");
        }
        SysPayConfig sysPayConfig = sysConfigService.getSysConfigObject(Constant.PAY_SWITCH_CONFIG, SysPayConfig.class);
        String domainName = shopConfig.getDomain().getApiDomainName();
        // 如果是商家端需要回调，则使用商家端的地址
        if (Objects.nonNull(payInfo.getBackType()) && Objects.equals(payInfo.getBackType(), BackType.SHOP.value())) {
            domainName = shopConfig.getDomain().getMultishopDomainName();
        }
        String notifyUrl = domainName + payInfo.getApiNoticeUrl();
        PayType payType = PayType.instance(payInfo.getPayType());
        if (Objects.equals(payType, PayType.SCOREPAY)) {
            return ServerResponseEntity.success();
        }
        // 使用原生支付or通联支付
        PaySettlementConfig paySettlementConfig = sysConfigService.getSysConfigObject(Constant.PAY_SETTLEMENT_CONFIG, PaySettlementConfig.class);
        if (Objects.isNull(paySettlementConfig)
                || Objects.equals(paySettlementConfig.getPaySettlementType(), PaySysType.DEFAULT.value())) {
            return doOriginalPay(payInfo, notifyUrl, sysPayConfig);
        } else {
            payInfo.setApiNoticeUrl(notifyUrl);
            return allinpayManager.doAllinPay(payInfo);
        }
    }

    private ServerResponseEntity<?> doOriginalPay(PayInfoDto payInfo, String notifyUrl, SysPayConfig sysPayConfig) throws WxPayException, AlipayApiException {
        PayType payType = PayType.instance(payInfo.getPayType());
        if (PayType.isWxPay(payType)) {
            if (!sysPayConfig.getWxPaySwitch()) {
                throw new YamiShopBindException("yami.order.pay.type.check");
            }
            Integer wxPayVersion = shopConfig.getWxPay().getVersion();
            // v3需要的配置
            if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
                return doWxPayV3(payInfo, notifyUrl, payType);
            } else {
                return doWxPay(payInfo, notifyUrl, payType);
            }
        } else if (Objects.equals(payType, PayType.ALIPAY)) {
            if (!sysPayConfig.getAliPaySwitch()) {
                throw new YamiShopBindException("yami.order.pay.type.check");
            }
            //创建API对应的request
            AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
            //在公共参数中设置回跳和通知地址
            alipayRequest.setNotifyUrl(notifyUrl);
            alipayRequest.setReturnUrl(payInfo.getReturnUrl());
            AlipayTradePagePayModel alipayTradePagePayModel = new AlipayTradePagePayModel();
            alipayTradePagePayModel.setOutTradeNo(payInfo.getPayNo());
            alipayTradePagePayModel.setBody(payInfo.getBody());
            alipayTradePagePayModel.setSubject(payInfo.getBody());
            alipayTradePagePayModel.setTotalAmount(Double.toString(payInfo.getPayAmount()));
            alipayTradePagePayModel.setProductCode("FAST_INSTANT_TRADE_PAY");
            alipayRequest.setBizModel(alipayTradePagePayModel);
            return ServerResponseEntity.success(aliPayConfig.getAlipayClient().pageExecute(alipayRequest).getBody());
        } else if (Objects.equals(payType, PayType.ALIPAY_H5)) {
            if (!sysPayConfig.getAliPaySwitch()) {
                throw new YamiShopBindException("yami.order.pay.type.check");
            }
            AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
            alipayRequest.setNotifyUrl(notifyUrl);
            alipayRequest.setReturnUrl(payInfo.getReturnUrl());
            AlipayTradeWapPayModel alipayTradeWapPayModel = new AlipayTradeWapPayModel();
            alipayTradeWapPayModel.setOutTradeNo(payInfo.getPayNo());
            alipayTradeWapPayModel.setSubject(payInfo.getBody());
            alipayTradeWapPayModel.setTotalAmount(Double.toString(payInfo.getPayAmount()));
            alipayTradeWapPayModel.setProductCode("QUICK_WAP_PAY");
            alipayRequest.setBizModel(alipayTradeWapPayModel);
            return ServerResponseEntity.success(aliPayConfig.getAlipayClient().pageExecute(alipayRequest).getBody());
        }
        // 支付宝app支付
        else if (Objects.equals(payType, PayType.ALIPAY_APP)) {
            if (!sysPayConfig.getAliPaySwitch()) {
                throw new YamiShopBindException("yami.order.pay.type.check");
            }
            AlipayTradeAppPayRequest alipayRequest = new AlipayTradeAppPayRequest();
            alipayRequest.setNotifyUrl(notifyUrl);
            AlipayTradeAppPayModel alipayTradeAppPayModel = new AlipayTradeAppPayModel();
            alipayTradeAppPayModel.setOutTradeNo(payInfo.getPayNo());
            alipayTradeAppPayModel.setSubject(payInfo.getBody());
            alipayTradeAppPayModel.setTotalAmount(Double.toString(payInfo.getPayAmount()));
            alipayTradeAppPayModel.setProductCode("QUICK_MSECURITY_PAY");
            alipayRequest.setBizModel(alipayTradeAppPayModel);
            String body = aliPayConfig.getAlipayClient().sdkExecute(alipayRequest).getBody();
            return ServerResponseEntity.success(body);
        }
        //余额支付
        else if (Objects.equals(payType, PayType.BALANCE)) {
            if (!sysPayConfig.getBalancePaySwitch()) {
                throw new YamiShopBindException("yami.order.pay.type.check");
            }
            PayInfoParam payInfoParam = new PayInfoParam();
            applicationContext.publishEvent(new BalancePayEvent(payInfo, payInfoParam));
            return ServerResponseEntity.success(payInfoParam);
        }
        //PayPal支付
        else if (Objects.equals(payType, PayType.PAYPAL)) {
            return doPayPalPay(payInfo, sysPayConfig, notifyUrl);
        }
        // 一般是积分支付才会到这一步
        return ServerResponseEntity.success();
    }

    private ServerResponseEntity<String> doPayPalPay(PayInfoDto payInfoDto, SysPayConfig sysPayConfig, String notifyUrl) {
        if (!sysPayConfig.getPayPalSwitch()) {
            throw new YamiShopBindException("yami.order.pay.type.check");
        }
        payInfoDto.setApiNoticeUrl(notifyUrl);
        OrdersCreateRequest request = payPalConfig.createPayPalOrder(payInfoDto);
        PayPalOrderParam param = payPalConfig.getExcetuteHref(request);
        // 根据支付单号，更新第三方订单号
        PayInfo payInfo = payInfoMapper.selectOne(new LambdaQueryWrapper<PayInfo>().eq(PayInfo::getPayNo, payInfoDto.getPayNo()));
        payInfo.setBizOrderNo(param.getOrderId());
        int updateCount = payInfoMapper.update(payInfo, Wrappers.lambdaUpdate(PayInfo.class)
                .eq(PayInfo::getPayNo, payInfoDto.getPayNo()));
        if (updateCount < 1) {
            // 支付信息更新失败
            throw new YamiShopBindException("yami.shop.pay.info.update.error");
        }
        // 创建钩子，如果已经在paypal配置好钩子可以将下面一行注释掉
        payPalConfig.createWebhook(payInfoDto.getApiNoticeUrl());
        return ServerResponseEntity.success(param.getHref());
    }

    private ServerResponseEntity<?> doWxPay(PayInfoDto payInfo, String notifyUrl, PayType payType) throws WxPayException {
        WxPayService wxPayService = wxConfig.getWxPayService(payType);
        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        orderRequest.setBody(payInfo.getBody());
        orderRequest.setOutTradeNo(payInfo.getPayNo());
        orderRequest.setTotalFee((int) Arith.mul(payInfo.getPayAmount(), 100));
        orderRequest.setSpbillCreateIp(IpHelper.getIpAddr());
        orderRequest.setOpenid(payInfo.getBizUserId());
        orderRequest.setNotifyUrl(notifyUrl);

        // 微信小程序支付 || 微信公众号支付
        if (Objects.equals(payType, PayType.WECHATPAY) || Objects.equals(payType, PayType.WECHATPAY_MP)) {
            orderRequest.setTradeType(WxPayConstants.TradeType.JSAPI);
            WxPayMpOrderResult wxPayMpOrderResult = wxPayService.createOrder(orderRequest);
            return ServerResponseEntity.success(wxPayMpOrderResult);
        }
        // 微信网页支付
        else if (Objects.equals(payType, PayType.WECHATPAY_SWEEP_CODE)) {
            orderRequest.setProductId(payInfo.getPayNo());
            // 生成微信二维码
            orderRequest.setTradeType(WxPayConstants.TradeType.NATIVE);
            WxPayNativeOrderResult wxPayNativeOrderResult = wxPayService.createOrder(orderRequest);

            return ServerResponseEntity.success(wxPayNativeOrderResult.getCodeUrl());
        }
        // 微信H5支付
        else if (Objects.equals(payType, PayType.WECHATPAY_H5)) {
            // 生成微信二维码
            orderRequest.setTradeType(WxPayConstants.TradeType.MWEB);
            String s = "{\"h5_info\": {\"type\":\"Wap\",\"wap_url\": \"\",\"wap_name\": \"\"}}";
            orderRequest.setSceneInfo(s);
            WxPayMwebOrderResult wxPayMwebOrderResult = wxPayService.createOrder(orderRequest);
            return ServerResponseEntity.success(wxPayMwebOrderResult.getMwebUrl());
        }
        // 微信app支付
        else if (Objects.equals(payType, PayType.WECHATPAY_APP)) {
            orderRequest.setTradeType(WxPayConstants.TradeType.APP);
            WxPayAppOrderResult wxPayAppOrderResult = wxPayService.createOrder(orderRequest);
            return ServerResponseEntity.success(wxPayAppOrderResult);
        }
        return null;
    }

    private ServerResponseEntity<?> doWxPayV3(PayInfoDto payInfo, String notifyUrl, PayType payType) throws WxPayException {
        WxPayService wxPayService = wxConfig.getWxPayService(payType);
        WxPayUnifiedOrderV3Request orderRequest = new WxPayUnifiedOrderV3Request();
        orderRequest.setDescription(payInfo.getBody());
        orderRequest.setOutTradeNo(payInfo.getPayNo());
        orderRequest.setNotifyUrl(notifyUrl);
        orderRequest.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal((int) Arith.mul(payInfo.getPayAmount(), 100)));

        // 微信小程序支付 || 微信公众号支付
        if (Objects.equals(payType, PayType.WECHATPAY) || Objects.equals(payType, PayType.WECHATPAY_MP)) {
            orderRequest.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(payInfo.getBizUserId()));
            return ServerResponseEntity.success(wxPayService.createOrderV3(TradeTypeEnum.JSAPI, orderRequest));
        }
        // 微信网页支付
        else if (Objects.equals(payType, PayType.WECHATPAY_SWEEP_CODE)) {
            // 生成微信二维码
            return ServerResponseEntity.success(wxPayService.createOrderV3(TradeTypeEnum.NATIVE, orderRequest));
        }
        // 微信H5支付
        else if (Objects.equals(payType, PayType.WECHATPAY_H5)) {
            orderRequest.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo()
                    .setPayerClientIp(IpHelper.getIpAddr())
                    .setH5Info(new WxPayUnifiedOrderV3Request.H5Info().setType("Wap")));
            // 生成h5支付地址
            return ServerResponseEntity.success(wxPayService.createOrderV3(TradeTypeEnum.H5, orderRequest));
        }
        // 微信app支付
        else if (Objects.equals(payType, PayType.WECHATPAY_APP)) {
            return ServerResponseEntity.success(wxPayService.createOrderV3(TradeTypeEnum.APP, orderRequest));
        }
        return null;
    }

    /**
     * 校验支付结果，并返回支付单号
     */
    public PayInfoResultBO validateAndGetPayInfo(Integer paySysType, HttpServletRequest request, PayType payType, String data) throws UnsupportedEncodingException, WxPayException, AlipayApiException {
        if (Objects.equals(paySysType, PaySysType.ALLINPAY.value())) {
            logger.info("通联支付回调开始, 回调内容为: {}", JSON.toJSONString(request.getParameterMap()));
            // 通联回调校验
            return validateAllinpay(data, request);
        }

        PayInfoResultBO payInfoResultBO = new PayInfoResultBO();
        // 支付回调数据
        handlePayInfo(payType, data, request, payInfoResultBO);

        if (StrUtil.isNotBlank(payInfoResultBO.getCallbackContent())) {
            PayInfo payInfo = new PayInfo();
            payInfo.setPayNo(payInfoResultBO.getPayNo());
            payInfo.setBizPayNo(payInfoResultBO.getBizPayNo());
            payInfo.setBizOrderNo(payInfoResultBO.getBizOrderNo());
            payInfo.setCallbackTime(new Date());
            payInfo.setCallbackContent(payInfoResultBO.getCallbackContent());
            // 支付宝多次回调可能该支付单已经退款，但还是更新了回调时间导致对账查询有误
            payInfoMapper.update(payInfo, new LambdaUpdateWrapper<PayInfo>()
                    .eq(PayInfo::getPayNo, payInfo.getPayNo())
                    .eq(PayInfo::getPayStatus, PayStatus.UNPAY.value()));
        }
        return payInfoResultBO;
    }

    private void handlePayInfo(PayType payType, String data, HttpServletRequest request, PayInfoResultBO payInfoResultBO) throws UnsupportedEncodingException, WxPayException, AlipayApiException {
        if (PayType.isWxPay(payType)) {
            WxPayService wxPayService = wxConfig.getWxPayService(payType);
            Integer wxPayVersion = shopConfig.getWxPay().getVersion();
            // v3需要的配置
            if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
                WxPayNotifyV3Result wxPayOrderNotifyV3Result = wxPayService.parseOrderNotifyV3Result(data, getSignatureHeader(request));
                payInfoResultBO.setPayNo(wxPayOrderNotifyV3Result.getResult().getOutTradeNo());
                payInfoResultBO.setBizPayNo(wxPayOrderNotifyV3Result.getResult().getTransactionId());
                payInfoResultBO.setIsPaySuccess(SUCCESS.equals(wxPayOrderNotifyV3Result.getResult().getTradeState()));
                // 返回200就行，无需内容
                payInfoResultBO.setPayAmount(Arith.div(wxPayOrderNotifyV3Result.getResult().getAmount().getTotal(), 100));
                payInfoResultBO.setCallbackContent(data);
            } else {
                WxPayOrderNotifyResult parseOrderNotifyResult = wxPayService.parseOrderNotifyResult(data);
                payInfoResultBO.setPayNo(parseOrderNotifyResult.getOutTradeNo());
                payInfoResultBO.setBizPayNo(parseOrderNotifyResult.getTransactionId());
                payInfoResultBO.setIsPaySuccess(SUCCESS.equals(parseOrderNotifyResult.getResultCode()));
                payInfoResultBO.setSuccessString(WX_SUCCESS_XML);
                payInfoResultBO.setPayAmount(Arith.div(parseOrderNotifyResult.getTotalFee(), 100));
                payInfoResultBO.setCallbackContent(data);
            }
        } else if (PayType.isAliPay(payType)) {
            //获取支付宝POST过来反馈信息
            Map<String, String> params = parseAliNotifyAndGetResult(request);
            //商户订单号,之前生成的带用户ID的订单号
            payInfoResultBO.setPayNo(params.get("out_trade_no"));
            //支付宝交易号
            payInfoResultBO.setBizPayNo(params.get("trade_no"));
            payInfoResultBO.setIsPaySuccess(true);
            payInfoResultBO.setSuccessString(ALI_SUCCESS);
            payInfoResultBO.setPayAmount(new BigDecimal(params.get("total_amount")).doubleValue());
            // 这个不是支付宝退款的通知
            if (StrUtil.isBlank(params.get(REFUND_FEE))) {
                payInfoResultBO.setIsPaySuccess(Objects.equals(params.get(TRADE_STATUS), TRADE_SUCCESS));
            } else {
                // 支付宝退款回调
                boolean isAliAllRefund = Objects.equals(params.get(TRADE_STATUS), TRADE_CLOSED) && StrUtil.isNotBlank(params.get(GMT_CLOSE));
                if (Objects.equals(params.get(TRADE_STATUS), TRADE_SUCCESS) || isAliAllRefund) {
                    payInfoResultBO.setIsPaySuccess(true);
                    payInfoResultBO.setIsAliRefund(true);
                    payInfoResultBO.setRefundSn(params.get("out_biz_no"));
                } else {
                    payInfoResultBO.setIsPaySuccess(false);
                }
            }
            payInfoResultBO.setCallbackContent(Json.toJsonString(params));
        } else if (Objects.equals(payType, PayType.PAYPAL)) {
            // webhook 回调
            Map<String, String> headers = payPalConfig.getHeadersInfo(request);
            WebhookParam webhookParam = JSON.parseObject(data, WebhookParam.class);
            boolean isVerify = payPalConfig.verifyWebhookSign(request, headers, data);
            if (!isVerify) {
                // 验签失败
                throw new YamiShopBindException("yami.sign.check");
            }
            String bizOrderNo = webhookParam.getResource().getId();
            if (StrUtil.isNotBlank(bizOrderNo)) {
                // 查询是否支付完成如果系统订单是已经支付完成就退款
                PayInfo payInfo = payInfoMapper.selectOne(Wrappers.lambdaQuery(PayInfo.class)
                        .eq(PayInfo::getBizOrderNo, bizOrderNo).last("limit 1"));
                if (Objects.isNull(payInfo)) {
                    // 找不到支付记录
                    throw new YamiShopBindException("找不到支付记录" + data);
                }
                if (Objects.equals(PayStatus.PAYED.value(), payInfo.getPayStatus())) {
                    // 已支付完成,支付失败，订单不在未支付状态
                    throw new YamiShopBindException("yami.order.pay.fail");
                }
                // 执行扣款操作
                payInfoResultBO = payPalConfig.captureOrder(bizOrderNo);
            } else {
                payInfoResultBO.setIsPaySuccess(false);
            }
            payInfoResultBO.setCallbackContent(data);
        }
    }

    @NotNull
    private SignatureHeader getSignatureHeader(HttpServletRequest request) {
        SignatureHeader signatureHeader = new SignatureHeader();
        signatureHeader.setSignature(request.getHeader("Wechatpay-Signature"));
        signatureHeader.setNonce(request.getHeader("Wechatpay-Nonce"));
        signatureHeader.setTimeStamp(request.getHeader("Wechatpay-TimeStamp"));
        signatureHeader.setSerial(request.getHeader("Wechatpay-Serial"));
        return signatureHeader;
    }

    public boolean doRefund(RefundInfoDto refundInfo) {

        PayType payType = refundInfo.getPayType();
        if (Objects.equals(refundInfo.getRefundAmount(), 0.0)) {
            return true;
        }
        Domain domain = shopConfig.getDomain();
        // 提交提款操作
        try {
            if (PayType.isWxPay(payType)) {
                // 订单金额
                double totalFee = Arith.mul(refundInfo.getPayAmount(), 100);
                // 退款金额
                double refundFee = Arith.mul(refundInfo.getRefundAmount(), 100);
                WxPayService wxPayService = wxConfig.getWxPayService(payType);
                Integer wxPayVersion = shopConfig.getWxPay().getVersion();
                if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
                    WxPayRefundV3Request wxPayRefundV3Request = new WxPayRefundV3Request();
                    wxPayRefundV3Request.setOutTradeNo(refundInfo.getPayNo());
                    wxPayRefundV3Request.setAmount(new WxPayRefundV3Request.Amount().setTotal((int) totalFee).setRefund((int) refundFee).setCurrency("CNY"));
                    wxPayRefundV3Request.setOutRefundNo(refundInfo.getRefundSn());
                    // notifyUrl（通知结果）
                    if (!Objects.equals(refundInfo.getOnlyRefund(), 1) && !Objects.equals(refundInfo.getRefundType(), RefundKindEnum.REPEAT_PAY.value())) {
                        // 只进行退款，不需要任何回调
                        wxPayRefundV3Request.setNotifyUrl(domain.getMultishopDomainName() + refundInfo.getNotifyUrl());
                    }
                    wxPayService.refundV3(wxPayRefundV3Request);
                } else {
                    // 退款操作
                    // 生成退款请求对象
                    WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
                    // 商户订单号
                    wxPayRefundRequest.setOutTradeNo(refundInfo.getPayNo());
                    wxPayRefundRequest.setTotalFee((int) totalFee);
                    wxPayRefundRequest.setRefundFee((int) refundFee);
                    // 退款编码
                    wxPayRefundRequest.setOutRefundNo(refundInfo.getRefundSn());

                    // notifyUrl（通知结果）
                    if (!Objects.equals(refundInfo.getOnlyRefund(), 1)) {
                        // 只进行退款，不需要任何回调
                        wxPayRefundRequest.setNotifyUrl(domain.getMultishopDomainName() + refundInfo.getNotifyUrl());
                    }
                    wxPayService.refund(wxPayRefundRequest);
                }
            } else if (PayType.isAliPay(payType)) {
                AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
                AlipayTradeRefundModel alipayTradeRefundModel = new AlipayTradeRefundModel();
                alipayTradeRefundModel.setOutTradeNo(refundInfo.getPayNo());
                alipayTradeRefundModel.setOutRequestNo(refundInfo.getRefundSn());
                alipayTradeRefundModel.setRefundAmount(Double.toString(refundInfo.getRefundAmount()));
                request.setBizModel(alipayTradeRefundModel);
                // 支付宝使用回调验证退款，回调地址为支付的时候填的回调地址，支付宝电脑支付全额退款没有回调，通过定时任务updateAliPayRefundStatus处理
                AlipayTradeRefundResponse response = aliPayConfig.getAlipayClient().certificateExecute(request);
                if (!response.isSuccess()) {
                    logger.error("阿里退款发生错误：{}", response.getMsg());
                    throw new YamiShopBindException(response.getMsg());
                }
            } else if (Objects.equals(payType, PayType.BALANCE)) {
                applicationContext.publishEvent(new BalanceRefundEvent(refundInfo));
            } else if (Objects.equals(payType, PayType.PAYPAL)) {
                // payPal申请退款
                return payPalConfig.refundOrder(refundInfo);
            }
        } catch (WxPayException e) {
            logger.error("微信退款发生错误：", e);
            throw new YamiShopBindException(e.getCustomErrorMsg(), e);
        } catch (AlipayApiException e) {
            logger.error("阿里退款发生错误：", e);
            throw new YamiShopBindException(e.getErrMsg(), e);
        }
        return false;
    }


    /**
     * 汇付天下的退款
     *
     * @param refundInfo
     * @return
     */
    public boolean doRefunds(RefundInfoDto refundInfo, Boolean isSettled, Map<String, Object> extendInfoMap) {

        PayType payType = refundInfo.getPayType();
        Domain domain = shopConfig.getDomain();
        if (Objects.equals(refundInfo.getRefundAmount(), 0.0)) {
            return true;
        }
        if (Objects.equals(payType, PayType.BALANCE)) {
            applicationContext.publishEvent(new BalanceRefundEvent(refundInfo));
            return false;
        }
        try {
            // 1. 数据初始化
            doInit(OppsMerchantConfigDemo.getMerchantConfig());
            PayInfo payInfo = payInfoMapper.selectOne(new LambdaQueryWrapper<PayInfo>()
                    .eq(PayInfo::getPayNo, refundInfo.getPayNo()));
            // 第三方paypal的交易号
            String captureId = refundInfo.getBizPayNo();
            // payNo 本系统生成的流水号
            String payNo = refundInfo.getPayNo();
            Map<String, Object> response = new HashMap<>();
            //已经结算了
            if (isSettled) {
                //V2TradePaymentDelaytransConfirmrefundqueryRequest
                V2TradePaymentDelaytransConfirmrefundRequest confirmrefundRequest = new V2TradePaymentDelaytransConfirmrefundRequest();
                confirmrefundRequest.setReqDate(refundInfo.getReqDate());
                // 请求流水号
                confirmrefundRequest.setReqSeqId(refundInfo.getRefundSn());
                // 商户号
                confirmrefundRequest.setHuifuId(DemoTestConstants.DEMO_SYS_ID);
                // 申请退款金额
                // 原交易请求日期
                confirmrefundRequest.setOrgReqDate(payInfo.getReqDate());
                confirmrefundRequest.setOrgReqSeqId(captureId);

                confirmrefundRequest.setExtendInfo(extendInfoMap);
                // 3. 发起API调用
                response = doExecute(confirmrefundRequest);
            } else {
                // 2.组装请求参数
                V2TradePaymentScanpayRefundRequest request = new V2TradePaymentScanpayRefundRequest();
                // 请求日期
                request.setReqDate(refundInfo.getReqDate());

                // 请求流水号
                request.setReqSeqId(refundInfo.getRefundSn());
                // 商户号
                request.setHuifuId(DemoTestConstants.DEMO_SYS_ID);
                // 申请退款金额
                request.setOrdAmt(BigDecimal.valueOf(refundInfo.getRefundAmount()).setScale(2, RoundingMode.HALF_UP) + "");
                // 原交易请求日期
                request.setOrgReqDate(payInfo.getReqDate());
                // 设置非必填字段

                request.setExtendInfo(extendInfoMap);
                // 3. 发起API调用
                response = doExecute(request);
            }


            log.info("返回数据:" + JSONObject.toJSONString(response));
            String subRespCode = (String) response.get("resp_code");
            if (subRespCode.equals("00000000")) {
                if (response.get("trans_stat").equals("P")) {
                    return false;
                }
                if (response.get("trans_stat").equals("S")) {
                    return true;
                }
                if (response.get("trans_stat").equals("F")) {
                    return false;
                }

            } else if (subRespCode.equals("00000100")) {
                log.info("交易处理中， 业务返回码=" + subRespCode + ",业务返回描述=" + subRespCode);
                return false;
            } else {
                    log.info("交易失败，业务返回码=" + subRespCode + ",业务返回描述=" + subRespCode);
                    throw new YamiShopBindException("业务返回码：" + subRespCode + ",业务描述：" + subRespCode + "。请联系客服处理！");
            }


        } catch (Exception e) {
            log.info("退款失败：" + e.getMessage() + ExceptionUtils.getRunException(e));
            throw new YamiShopBindException(e.getMessage(), e);
        }

        return false;
    }


    public RefundInfoBo validateAndGetRefundInfo(HttpServletRequest request, Integer paySysType, PayType payType, String data) throws UnsupportedEncodingException, WxPayException, AlipayApiException {
        if (Objects.equals(paySysType, PaySysType.ALLINPAY.value())) {
            // 通联回调校验
            return validateRefundAllinpay(data, request);
        }
        RefundInfoBo refundInfoBo = new RefundInfoBo();
        refundInfoBo.setIsRefundSuccess(false);

        if (PayType.isWxPay(payType)) {
            Integer wxPayVersion = shopConfig.getWxPay().getVersion();
            WxPayService wxPayService = wxConfig.getWxPayService(payType);
            if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
                WxPayRefundNotifyV3Result wxPayRefundNotifyV3Result = wxPayService.parseRefundNotifyV3Result(data, getSignatureHeader(request));
                WxPayRefundNotifyV3Result.DecryptNotifyResult result = wxPayRefundNotifyV3Result.getResult();
                if (Constant.SUCCESS.equals(result.getRefundStatus())) {
                    refundInfoBo.setIsRefundSuccess(true);
                    refundInfoBo.setSuccessString(WX_SUCCESS_XML);
                    refundInfoBo.setRefundNo(result.getOutRefundNo());
                    refundInfoBo.setBizRefundNo(result.getRefundId());
                    refundInfoBo.setCallbackContent(data);
                }
            } else {
                WxPayRefundNotifyResult wxPayRefundNotifyResult = wxPayService.parseRefundNotifyResult(data);
                WxPayRefundNotifyResult.ReqInfo reqInfo = wxPayRefundNotifyResult.getReqInfo();
                if (Constant.SUCCESS.equals(reqInfo.getRefundStatus())) {
                    refundInfoBo.setIsRefundSuccess(true);
                    refundInfoBo.setSuccessString(WX_SUCCESS_XML);
                    refundInfoBo.setRefundNo(reqInfo.getOutRefundNo());
                    refundInfoBo.setBizRefundNo(reqInfo.getRefundId());
                    refundInfoBo.setCallbackContent(data);
                }
            }
        } else if (PayType.isAliPay(payType)) {
            Map<String, String> params = parseAliNotifyAndGetResult(request);
            if (Objects.equals(params.get(TRADE_STATUS), TRADE_SUCCESS) || Objects.equals(params.get(TRADE_STATUS), TRADE_CLOSED)) {
                refundInfoBo.setIsRefundSuccess(true);
                refundInfoBo.setRefundNo(params.get("out_biz_no"));
                refundInfoBo.setBizRefundNo("");
                refundInfoBo.setSuccessString(ALI_SUCCESS);
                refundInfoBo.setCallbackContent(Json.toJsonString(params));
            }
        }
        return refundInfoBo;
    }

    public RefundInfoBo validateDukPayAndGetRefundInfo(HttpServletRequest request, Integer paySysType, PayType payType, String data) {
        RefundInfoBo refundInfoBo = new RefundInfoBo();
        refundInfoBo.setIsRefundSuccess(false);
        log.info("回调数据:request.getParameter(resp_code)========================================================" + request.getParameter("resp_code"));
        log.info("回调数据:request.getParameter(resp_desc)========================================================" + request.getParameter("resp_desc"));
        log.info("回调数据:request.getParameter(sign)========================================================" + request.getParameter("sign"));
        log.info("回调数据:request.getParameter(resp_data)======================================================" + request.getParameter("resp_data"));
        JSONObject respData = JSONObject.parseObject(request.getParameter("resp_data"));
        String respCode = request.getParameter("resp_code");

//        boolean sign = RsaUtils.verify(request.getParameter("resp_data"), Base64.getEncoder().encodeToString(DemoTestConstants.DEMO_RSA_PUBLIC_KEY.getBytes(StandardCharsets.UTF_8)), request.getParameter("sign"));
//        if(!sign){
//            throw new RuntimeException("签名验证失败");
//        }

//        boolean sign = RsaUtils.verify(request.getParameter("resp_data"), DemoTestConstants.DEMO_RSA_PUBLIC_KEY, request.getParameter("sign"));
//        System.out.println("签名验证结果:==========================================================="+sign);
//        if(!sign){
//            throw new RuntimeException("签名验证失败");
//        }

        if (respCode.equals("00000000") && respData.get("trans_stat").equals("S")) {
            refundInfoBo.setIsRefundSuccess(true);
            refundInfoBo.setRefundNo(respData.get("req_seq_id").toString());
            refundInfoBo.setBizRefundNo(respData.get("req_seq_id").toString());
            refundInfoBo.setSuccessString("RECV_ORD_ID_" + respData.get("req_seq_id").toString());
            refundInfoBo.setCallbackContent(Json.toJsonString(respData));
        } else {
            refundInfoBo.setRefundNo(respData.get("req_seq_id").toString());
            refundInfoBo.setBizRefundNo(respData.get("req_seq_id").toString());
            refundInfoBo.setSuccessString("RECV_ORD_ID_" + respData.get("req_seq_id").toString());
            refundInfoBo.setCallbackContent(Json.toJsonString(respData));
        }
        log.info("方法结束==================================================");
        return refundInfoBo;
    }

    private RefundInfoBo validateRefundAllinpay(String data, HttpServletRequest request) throws UnsupportedEncodingException {
        RefundInfoBo refundInfoResultBo = new RefundInfoBo();
        //获取支付宝POST过来反馈信息
        Map<String, String> params = allinpayConfig.getParams(request);
        logger.info("data:{}", data);

        if (!allinpayConfig.signVerify(params)) {
            // 验签失败
            refundInfoResultBo.setIsRefundSuccess(false);
            return refundInfoResultBo;
        }
        String paramsStr = JSON.toJSONString(params, SerializerFeature.MapSortField);
        OpenRequest openRequest = JSONObject.parseObject(paramsStr, OpenRequest.class);
        // 2.转换成bean
        AllinpayResp allinpayResp = JSON.parseObject(openRequest.getBizContent(), AllinpayResp.class);


        refundInfoResultBo.setIsRefundSuccess(ALLINPAY_SUCCESS.equals(allinpayResp.getStatus()));
        refundInfoResultBo.setSuccessString(WX_SUCCESS_XML);
//        String[] bizOrderNumbers = allinpayResp.getBizOrderNo().split(StrUtil.UNDERLINE);
        String bizOrderNo = allinpayResp.getBizOrderNo().replace(SegmentIdKey.REFUND, "");
        refundInfoResultBo.setRefundNo(bizOrderNo);
        refundInfoResultBo.setBizRefundNo(allinpayResp.getOrderNo());
        refundInfoResultBo.setCallbackContent(data);
        return refundInfoResultBo;
    }

    /**
     * 原来的查单  是否支付成功数据
     *
     * @param payType
     * @param payNo
     * @param paySysType
     * @param bizPayNo
     * @return
     */
    public PayInfoResultBO getPayInfo(PayType payType, String payNo, Integer paySysType, String bizPayNo) {
        PayInfoResultBO payInfo = new PayInfoResultBO();
        payInfo.setPayNo(payNo);
        payInfo.setBizPayNo(bizPayNo);
        payInfo.setPaySysType(paySysType);
        if (Objects.equals(paySysType, PaySysType.ALLINPAY.value())) {
            OrderStatusResp orderStatusResp = allinpayManager.getOrderStatus(payNo);
            payInfo.setIsPaySuccess(false);
            if (Objects.nonNull(orderStatusResp) && Objects.equals(orderStatusResp.getOrderStatus(), ALLINPAY_ORDER_SUCCESS)) {
                payInfo.setBizPayNo(orderStatusResp.getOrderNo());
                payInfo.setIsPaySuccess(true);
            }
            return payInfo;
        }
        try {
            if (PayType.isWxPay(payType)) {
                Integer wxPayVersion = shopConfig.getWxPay().getVersion();
                WxPayService wxPayService = wxConfig.getWxPayService(payType);
                // v3需要的配置
                if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
                    WxPayOrderQueryV3Result wxPayOrderQueryV3Result = wxPayService.queryOrderV3(null, payNo);
                    if (!Objects.isNull(wxPayOrderQueryV3Result) && Objects.equals(wxPayOrderQueryV3Result.getTradeState(), Constant.SUCCESS)) {
                        payInfo.setBizPayNo(wxPayOrderQueryV3Result.getTransactionId());
                        payInfo.setIsPaySuccess(true);
                    } else {
                        payInfo.setIsPaySuccess(false);
                    }
                } else {
                    WxPayOrderQueryResult wxPayOrderQueryResult = wxPayService.queryOrder(null, payNo);
                    if (!Objects.isNull(wxPayOrderQueryResult) && Objects.equals(wxPayOrderQueryResult.getTradeState(), Constant.SUCCESS)) {
                        payInfo.setBizPayNo(wxPayOrderQueryResult.getTransactionId());
                        payInfo.setIsPaySuccess(true);
                    } else {
                        payInfo.setIsPaySuccess(false);
                    }
                }
            } else if (PayType.isAliPay(payType)) {
                AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
                AlipayTradeQueryModel alipayTradeQueryModel = new AlipayTradeQueryModel();
                alipayTradeQueryModel.setOutTradeNo(payNo);

                request.setBizModel(alipayTradeQueryModel);
                AlipayTradeQueryResponse response = aliPayConfig.getAlipayClient().certificateExecute(request);
                if (response.isSuccess() && Objects.equals(response.getTradeStatus(), TRADE_SUCCESS)) {
                    payInfo.setBizPayNo(response.getTradeNo());
                    payInfo.setIsPaySuccess(true);
                } else {
                    payInfo.setIsPaySuccess(false);
                }
            } else if (Objects.equals(payType, PayType.PAYPAL)) {
                // paypal查单
                if (Objects.isNull(bizPayNo)) {
                    payInfo.setIsPaySuccess(false);
                    return payInfo;
                }
                payPalConfig.getCapture(payInfo);
            } else {
                payInfo.setIsPaySuccess(false);
            }
        } catch (WxPayException | AlipayApiException e) {
            logger.error("获取支付信息错误：", e);
            payInfo.setIsPaySuccess(false);
        }
        return payInfo;
    }

    /**
     * 汇付的查单数据
     *
     * @param payType
     * @param payNo
     * @param paySysType
     * @param bizPayNo
     * @return
     */
    public PayInfoResultBO getPayHuiFuInfo(PayType payType, String payNo, Integer paySysType, String bizPayNo, String reqDate) {
        PayInfoResultBO payInfo = new PayInfoResultBO();
        payInfo.setPayNo(payNo);
        payInfo.setBizPayNo(bizPayNo);
        payInfo.setPaySysType(paySysType);
        if (Objects.isNull(reqDate) && Objects.isNull(bizPayNo)) {
            payInfo.setIsPaySuccess(false);
            logger.info("交易失败= reqDate 和bizPayNo 为空或者null ，不在进行查询交易信息");
            return payInfo;
        }
        //获取支付信息
        // 根据之前的支付信息查询是否支付
        try {  // 1. 设置商户参数（全局只需设置一次）
            doInit(OppsMerchantConfigDemo.getMerchantConfig());
            V2TradePaymentScanpayQueryRequest request = new V2TradePaymentScanpayQueryRequest();
            request.setOrgReqSeqId(bizPayNo);
            request.setHuifuId(DemoTestConstants.DEMO_SYS_ID);
            request.setOrgReqDate(reqDate);
            // 3. 发起API调用
            Map<String, Object> response = doExecute(request);
            logger.info("调用汇付查询支付是否成功，更改状态:" + JSONObject.toJSONString(response));
            String subRespCode = (String) response.get("resp_code");
            if (subRespCode.equals("00000000")) {
                if (response.get("trans_stat").equals("P")) {
                    payInfo.setIsPaySuccess(false);
                }
                if (response.get("trans_stat").equals("S")) {
                    payInfo.setIsPaySuccess(true);
                }
                if (response.get("trans_stat").equals("F")) {
                    payInfo.setIsPaySuccess(false);
                }
                if (response.get("trans_stat").equals("I")) {
                    payInfo.setIsPaySuccess(false);
                    logger.error("交易初始状态，需要联系汇付客服处理。");
                }
                payInfo.setIsPaySuccess(false);
            } else {
                logger.error("交易失败，业务返回码=" + subRespCode + ",业务返回描述=" + response.get("resp_desc"));
                payInfo.setIsPaySuccess(false);
            }
        } catch (Exception e) {
            logger.error("交易查询失败，返回失败信息为：" + ExceptionUtils.getRunException(e));
            payInfo.setIsPaySuccess(false);
        }
        return payInfo;
    }


    /**
     * 获取退款信息
     */
    public RefundInfoBo getRefundInfo(PayType payType, String payNo, Integer paySysType, String refundSn) {
        RefundInfoBo refundInfoBo = new RefundInfoBo();
        PayInfo payInfo = payInfoMapper.selectOne(new LambdaQueryWrapper<PayInfo>()
                .eq(PayInfo::getPayNo, payNo));
        refundInfoBo.setRefundNo(refundSn);
        if (Objects.equals(paySysType, PaySysType.ALLINPAY.value())) {
            OrderStatusResp orderStatusResp = allinpayManager.getOrderStatus(SegmentIdKey.REFUND + refundSn);
            refundInfoBo.setIsRefundSuccess(false);
            if (Objects.nonNull(orderStatusResp) && Objects.equals(orderStatusResp.getOrderStatus(), ALLINPAY_ORDER_SUCCESS)) {
                refundInfoBo.setBizRefundNo(orderStatusResp.getOrderNo());
                refundInfoBo.setIsRefundSuccess(true);
            }
            return refundInfoBo;
        }
        try {
            if (PayType.isWxPay(payType)) {
                Integer wxPayVersion = shopConfig.getWxPay().getVersion();
                WxPayService wxPayService = wxConfig.getWxPayService(payType);
                // v3需要的配置
                if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
                    WxPayRefundQueryV3Result wxPayRefundQueryV3Result = wxPayService.refundQueryV3(refundSn);
                    if (Objects.nonNull(wxPayRefundQueryV3Result) && Objects.equals(wxPayRefundQueryV3Result.getStatus(), Constant.SUCCESS)) {
                        refundInfoBo.setBizRefundNo(wxPayRefundQueryV3Result.getRefundId());
                        refundInfoBo.setIsRefundSuccess(true);
                    } else {
                        refundInfoBo.setIsRefundSuccess(false);
                    }
                } else {
                    WxPayRefundQueryResult wxPayRefundQueryResult = wxPayService.refundQuery(null, null, refundSn, null);
                    if (Objects.isNull(wxPayRefundQueryResult) || CollUtil.isEmpty(wxPayRefundQueryResult.getRefundRecords())) {
                        refundInfoBo.setIsRefundSuccess(false);
                    } else {
                        WxPayRefundQueryResult.RefundRecord refundRecord = wxPayRefundQueryResult.getRefundRecords().get(0);
                        if (Objects.equals(refundRecord.getRefundStatus(), Constant.SUCCESS)) {
                            refundInfoBo.setBizRefundNo(refundRecord.getRefundId());
                            refundInfoBo.setIsRefundSuccess(true);
                        } else {
                            refundInfoBo.setIsRefundSuccess(false);
                        }
                    }
                }
            } else if (PayType.isAliPay(payType)) {
                AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
                AlipayTradeFastpayRefundQueryModel alipayTradeFastpayRefundQueryModel = new AlipayTradeFastpayRefundQueryModel();
                alipayTradeFastpayRefundQueryModel.setOutTradeNo(payNo);
                alipayTradeFastpayRefundQueryModel.setOutRequestNo(refundSn);
                request.setBizModel(alipayTradeFastpayRefundQueryModel);
                AlipayTradeFastpayRefundQueryResponse response = aliPayConfig.getAlipayClient().certificateExecute(request);
                if (response.isSuccess() && Objects.equals(response.getRefundStatus(), REFUND_SUCCESS)) {
                    refundInfoBo.setBizRefundNo(response.getTradeNo());
                    refundInfoBo.setIsRefundSuccess(true);
                } else {
                    refundInfoBo.setIsRefundSuccess(false);
                }
            } else {
                refundInfoBo.setIsRefundSuccess(false);
            }
        } catch (WxPayException | AlipayApiException e) {
            logger.error("获取退款信息错误：", e);
            refundInfoBo.setIsRefundSuccess(false);
        }
        return refundInfoBo;
    }

    /**
     * 获取退款信息 汇付退款信息查询
     */
    public RefundInfoBo getRefundHuiFuInfo(PayType payType, String payNo, Integer paySysType,
                                           String refundSn, String reqDate,
                                           Boolean isSettled, Map<String, Object> extendInfoMap) {
        RefundInfoBo refundInfoBo = new RefundInfoBo();
        PayInfo payInfo = payInfoMapper.selectOne(new LambdaQueryWrapper<PayInfo>()
                .eq(PayInfo::getPayNo, payNo));
        refundInfoBo.setRefundNo(refundSn);
        refundInfoBo.setBizRefundNo(refundSn);

        try {
            // 1. 数据初始化
            doInit(OppsMerchantConfigDemo.getMerchantConfig());
            Map<String, Object> response = new HashMap<>();
            //已经结算了
            if (isSettled) {
                //V2TradePaymentDelaytransConfirmrefundqueryRequest
                V2TradePaymentDelaytransConfirmrefundRequest confirmrefundRequest = new V2TradePaymentDelaytransConfirmrefundRequest();
                confirmrefundRequest.setReqDate(DateTools.getCurrentDateYYYYMMDD());
                // 请求流水号
                confirmrefundRequest.setReqSeqId(refundSn);
                // 商户号
                confirmrefundRequest.setHuifuId(DemoTestConstants.DEMO_SYS_ID);
                // 申请退款金额
                // 原交易请求日期
                confirmrefundRequest.setOrgReqDate(payInfo.getReqDate());
                confirmrefundRequest.setOrgReqSeqId(payInfo.getBizPayNo());

                confirmrefundRequest.setExtendInfo(extendInfoMap);
                // 3. 发起API调用
                response = doExecute(confirmrefundRequest);
            } else {
                V2TradePaymentScanpayRefundqueryRequest request = new V2TradePaymentScanpayRefundqueryRequest();

                request.setHuifuId(DemoTestConstants.DEMO_SYS_ID);
                request.setOrgReqDate(reqDate);
                request.setOrgReqSeqId(refundSn);
                request.setExtendInfo(extendInfoMap);
                response = doExecute(request);
            }
            // 3. 发起API调用

            logger.info("定时任务查询退款数据，返回数据:" + JSONObject.toJSONString(response));
            String subRespCode = (String) response.get("resp_code");
            if (subRespCode.equals("00000000")) {
                if (response.get("trans_stat").equals("P")) {
                    refundInfoBo.setIsRefundSuccess(false);
                    return refundInfoBo;
                }
                if (response.get("trans_stat").equals("S")) {
                    refundInfoBo.setIsRefundSuccess(true);
                    return refundInfoBo;
                }
                if (response.get("trans_stat").equals("F")) {
                    refundInfoBo.setIsRefundSuccess(false);
                    return refundInfoBo;
                }
                if (response.get("trans_stat").equals("I")) {
                    refundInfoBo.setIsRefundSuccess(false);
                    logger.error("交易初始状态，需要联系汇付客服处理。");
                    return refundInfoBo;
                }
                refundInfoBo.setIsRefundSuccess(false);
                return refundInfoBo;
            } else {
                logger.error("交易失败，业务返回码=" + subRespCode + ",业务返回描述=" + (String) response.get("sub_resp_desc"));
                refundInfoBo.setIsRefundSuccess(false);
                return refundInfoBo;
            }

        } catch (Exception e) {
            log.info("退款查询失败：" + e.getMessage() + ExceptionUtils.getRunException(e));
            refundInfoBo.setIsRefundSuccess(false);
            return refundInfoBo;
        }
    }

    public Boolean cancelOrderQrCode(List<PayInfo> payInfoList) {
        Integer wxPayVersion = shopConfig.getWxPay().getVersion();
        Map<Integer, List<PayInfo>> payTypeMap = payInfoList.stream().collect(Collectors.groupingBy(PayInfo::getPayType));
        for (Integer payType : payTypeMap.keySet()) {
            PayType type = PayType.instance(payType);
            List<PayInfo> infoList = payTypeMap.get(payType);
            //关闭扫码接口

            for (PayInfo payInfo : infoList) {
                V2TradePaymentScanpayClosequeryRequest request = new V2TradePaymentScanpayClosequeryRequest();

                // 请求日期
                request.setReqDate(DateTools.getCurrentDateYYYYMMDD());
                // 请求流水号
                request.setReqSeqId(SequenceTools.getReqSeqId32());
                // 商户号
                request.setHuifuId(DemoTestConstants.DEMO_SYS_ID);
                String reqDate = "";
                if (payInfo.getReqDate() == null || "".equals(payInfo.getReqDate())) {
                    reqDate = DateUtils.parseDateToStr("yyyyMMdd", payInfo.getCreateTime());
                } else {
                    reqDate = payInfo.getReqDate();
                }
                request.setOrgReqDate(reqDate);
                if (payInfo.getBizPayNo() == null || "".equals(payInfo.getBizPayNo())) {
                    continue;
                }
                Map<String, Object> extendInfoMap = new HashMap<>();
                extendInfoMap.put("org_req_seq_id", payInfo.getBizPayNo());
                request.setExtendInfo(extendInfoMap);
                // 3. 发起API调用
                Map<String, Object> response = null;
                try {
                    response = doExecute(request);
                    log.info("交易关单 返回数据:" + JSONObject.toJSONString(response));
                    String subRespCode = (String) response.get("resp_code");
                    if (subRespCode.equals("00000000")) {
                        if (response.get("trans_stat").equals("F")) {
                            return false;
                        }
                    }
                } catch (Exception e) {
                    logger.info("交易关单失败，----->" + ExceptionUtils.getRunException(e));
                    return false;
                }


                // if (PayType.isWxPay(type)) {
                //     WxPayService wxPayService = wxConfig.getWxPayService(type);
                //     // v3需要的配置
                //     if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
                //         wxPayService.closeOrderV3(payInfo.getPayNo());
                //     } else {
                //         wxPayService.closeOrder(payInfo.getPayNo());
                //     }
                // } else if (PayType.isAliPay(type)) {
                //     AlipayTradeCloseRequest tradeCloseRequest = new AlipayTradeCloseRequest();
                //     AlipayTradeCloseModel tradeCloseModel = new AlipayTradeCloseModel();
                //     tradeCloseModel.setOutTradeNo(payInfo.getPayNo());
                //     tradeCloseRequest.setBizModel(tradeCloseModel);
                //     AlipayTradeCloseResponse response = aliPayConfig.getAlipayClient().certificateExecute(tradeCloseRequest);
                //     logger.warn(response.getBody());
                //     if (!response.isSuccess()) {
                //         return false;
                //     }
                // }
            }
        }
        return true;
    }

    /**
     * 获取支付宝POST过来反馈信息
     *
     * @param request
     * @return
     * @throws UnsupportedEncodingException
     * @throws AlipayApiException
     */
    private Map<String, String> parseAliNotifyAndGetResult(HttpServletRequest request) throws UnsupportedEncodingException, AlipayApiException {
        Map<String, String> params = getRequestParamsMap(request);
        //调用SDK验证签名
        boolean signVerified;
        Alipay alipay = shopConfig.getAlipay();
        if (StrUtil.isBlank(alipay.getAlipayCertContent())) {
            signVerified = AlipaySignature.rsaCertCheckV1(params, alipay.getAlipayCertPath(), cn.hutool.core.util.CharsetUtil.UTF_8, AlipayConstants.SIGN_TYPE_RSA2);
        } else {
            String publicKey;
            try {
                publicKey = this.getPublicKeyByContent(alipay.getAlipayCertContent());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            signVerified = AlipaySignature.rsaCheckV1(params, publicKey, cn.hutool.core.util.CharsetUtil.UTF_8, AlipayConstants.SIGN_TYPE_RSA2);
        }
        if (!signVerified) {
            // 验签失败
            throw new YamiShopBindException("yami.sign.check");
        }
        return params;
    }

    private String getPublicKeyByContent(String content) throws Exception {
        InputStream inputStream = new ByteArrayInputStream(content.getBytes());
        CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
        X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
        PublicKey publicKey = cert.getPublicKey();
        return Base64.encodeBase64String(publicKey.getEncoded());
    }

    /**
     * 获取请求参数
     */
    private Map<String, String> getRequestParamsMap(HttpServletRequest request) throws UnsupportedEncodingException {
        //乱码解决，这段代码在出现乱码时使用
        request.setCharacterEncoding("utf-8");
        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<>(16);
        Map<String, String[]> requestParams = request.getParameterMap();
        for (String name : requestParams.keySet()) {
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        return params;
    }

    private PayInfoResultBO validateAllinpay(String data, HttpServletRequest request) throws UnsupportedEncodingException {
        // 验签
        OpenRequest openRequest = allinpayConfig.validateAllinpayAndReturn(data, request);
        // 2.转换成bean
        AllinpayResp allinpayResp = JSON.parseObject(openRequest.getBizContent(), AllinpayResp.class);
        PayInfoResultBO payInfoResultBO = new PayInfoResultBO();
        payInfoResultBO.setPayNo(allinpayResp.getBizOrderNo());
        payInfoResultBO.setBizPayNo(allinpayResp.getOrderNo());
        payInfoResultBO.setPayAmount(Arith.toDecimalPrice(allinpayResp.getAmount()).doubleValue());
        payInfoResultBO.setIsPaySuccess(Objects.equals(allinpayResp.getStatus(), ALLINPAY_SUCCESS));
        payInfoResultBO.setSuccessString(ALLINPAY_SUCCESS);
        payInfoResultBO.setCallbackContent(openRequest.getBizContent());
        payInfoResultBO.setPaySysType(PaySysType.ALLINPAY.value());
        payInfoResultBO.setExtendInfo(allinpayResp.getExtendInfo());
        // 修改支付信息
        PayInfo payInfo = new PayInfo();
        payInfo.setPayNo(payInfoResultBO.getPayNo());
        payInfo.setBizPayNo(payInfoResultBO.getBizPayNo());
        payInfo.setCallbackContent(Json.toJsonString(openRequest.getBizContent()));
        payInfo.setCallbackTime(new Date());
        payInfoMapper.update(payInfo, new LambdaUpdateWrapper<PayInfo>()
                .eq(PayInfo::getPayNo, payInfo.getPayNo()));
        return payInfoResultBO;
    }


}
